<template>
  <div class="product-bulk-upload">
    <el-card shadow="never">
      <template #header>
        <div class="flex justify-between items-center">
          <span>批量导入商品</span>
          <el-button type="primary" link @click="downloadTemplate">
            下载模板
          </el-button>
        </div>
      </template>

      <el-steps :active="currentStep" finish-status="success" align-center>
        <el-step title="上传文件" />
        <el-step title="字段映射" />
        <el-step title="数据预览" />
        <el-step title="完成导入" />
      </el-steps>

      <div v-show="currentStep === 0" class="step-section">
        <el-alert
          title="上传说明"
          type="info"
          :closable="false"
          show-icon
          class="mb-4"
        >
          支持 CSV、XLS、XLSX 格式，大小不超过 5MB。请确保文件首行包含表头信息。
        </el-alert>
        <el-form
          v-if="showSellerOrgSelector"
          label-width="100px"
          class="config-form mb-4"
        >
          <el-form-item label="卖家组织">
            <el-select
              v-model="sellerOrgId"
              placeholder="请选择卖家组织"
              filterable
              clearable
              remote
              :remote-method="handleSellerOrgSearch"
              :loading="sellerOrgLoading"
              class="w-[320px]!"
              @visible-change="handleSellerOrgVisibleChange"
            >
              <el-option
                v-for="item in sellerOrgOptions"
                :key="item.id"
                :label="item.name"
                :value="item.id"
              />
            </el-select>
            <span class="text-gray-500 text-sm ml-3"
              >请选择需要导入商品的卖家组织</span
            >
          </el-form-item>
        </el-form>
        <el-upload
          class="upload-box"
          drag
          :auto-upload="false"
          :limit="1"
          :show-file-list="true"
          :file-list="uploadFileList"
          :on-change="handleFileChange"
          :on-remove="resetFile"
          accept=".csv,.xls,.xlsx"
        >
          <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
          <div class="el-upload__text">
            拖拽文件到这里，或 <em>点击上传</em>
          </div>
          <template #tip>
            <div class="el-upload__tip">
              导入前请选择基础信息，并确认上传文件格式正确。
            </div>
          </template>
        </el-upload>
        <div v-if="fileHeaders.length" class="mt-4">
          <h4>已识别的表头：</h4>
          <el-tag v-for="header in fileHeaders" :key="header" class="mr-2 mb-2">
            {{ header }}
          </el-tag>
        </div>
      </div>

      <div v-show="currentStep === 1" class="step-section">
        <el-alert
          title="字段映射"
          type="info"
          :closable="false"
          show-icon
          class="mb-4"
        >
          请将文件中的表头与系统字段进行匹配，带 * 的为必填字段。
          <el-button type="primary" link @click="autoMapFields">
            自动匹配
          </el-button>
        </el-alert>
        <el-table :data="mappingFields" border>
          <el-table-column label="系统字段" width="220">
            <template #default="{ row }">
              <span :class="{ 'required-label': row.required }">
                {{ row.label }}
              </span>
              <span v-if="row.required" class="required-marker">*</span>
            </template>
          </el-table-column>
          <el-table-column label="文件表头">
            <template #default="{ row }">
              <el-select
                v-model="row.mappedHeader"
                placeholder="选择文件表头"
                clearable
                class="w-full"
                @change="buildPreviewData"
              >
                <el-option
                  v-for="header in fileHeaders"
                  :key="header"
                  :label="header"
                  :value="header"
                />
              </el-select>
            </template>
          </el-table-column>
          <el-table-column label="示例值">
            <template #default="{ row }">
              <span>{{ getExampleValue(row.mappedHeader) || "-" }}</span>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <div v-show="currentStep === 2" class="step-section">
        <el-alert
          v-if="previewData.length === 0"
          title="未获取到有效数据，请返回上一步重新上传"
          type="warning"
          :closable="false"
          show-icon
        />
        <template v-else>
          <el-alert
            :title="`共识别 ${previewData.length} 条数据，其中 ${invalidRowCount} 条存在问题`"
            type="info"
            :closable="false"
            show-icon
            class="mb-4"
          />
          <el-table
            v-loading="loadingPreview"
            :data="previewData"
            border
            max-height="420"
          >
            <el-table-column type="index" width="60" label="#" />
            <el-table-column
              v-for="field in mappedPreviewFields"
              :key="field.key"
              :prop="field.key"
              :label="field.label"
              min-width="160"
            />
            <el-table-column label="校验状态" width="120">
              <template #default="{ row }">
                <el-tag
                  v-if="validateRow(row).valid"
                  type="success"
                  size="small"
                  effect="plain"
                >
                  通过
                </el-tag>
                <el-tooltip
                  v-else
                  effect="dark"
                  placement="top"
                  :content="validateRow(row).errors.join('；')"
                >
                  <el-tag type="danger" size="small" effect="plain">
                    异常
                  </el-tag>
                </el-tooltip>
              </template>
            </el-table-column>
          </el-table>
        </template>
      </div>

      <div v-show="currentStep === 3" class="step-section">
        <el-result
          :icon="importResult.success ? 'success' : 'warning'"
          :title="importResult.title"
          :sub-title="importResult.subTitle"
        >
          <template #extra>
            <el-button type="primary" @click="resetAll">重新导入</el-button>
            <el-button @click="backToList">返回列表</el-button>
          </template>
        </el-result>
        <div v-if="importResult.errors.length" class="error-panel">
          <el-alert
            type="error"
            title="部分数据导入失败"
            :closable="false"
            show-icon
            class="mb-2"
          />
          <el-collapse>
            <el-collapse-item title="查看错误详情">
              <el-alert
                v-for="(item, index) in importResult.errors"
                :key="index"
                :title="item"
                type="error"
                :closable="false"
                show-icon
                class="mb-2"
              />
            </el-collapse-item>
          </el-collapse>
        </div>
      </div>

      <div class="step-actions">
        <el-button
          v-if="currentStep > 0 && currentStep < 3"
          :disabled="processing"
          @click="prevStep"
        >
          上一步
        </el-button>
        <el-button
          v-if="currentStep < 2"
          type="primary"
          :loading="processing"
          @click="nextStep"
        >
          下一步
        </el-button>
        <el-button
          v-if="currentStep === 2"
          type="primary"
          :loading="processing"
          @click="handleImport"
        >
          确认导入
        </el-button>
      </div>
    </el-card>

    <el-card shadow="never" class="job-card">
      <template #header>
        <div class="flex justify-between items-center">
          <span>导入任务列表</span>
          <el-button
            size="small"
            :loading="jobState.loading"
            @click="fetchJobList()"
          >
            刷新
          </el-button>
        </div>
      </template>

      <el-table
        v-loading="jobState.loading"
        :data="jobState.list"
        border
        empty-text="暂无任务"
      >
        <el-table-column prop="id" label="任务ID" width="90" />
        <el-table-column label="状态" width="120">
          <template #default="{ row }">
            <el-tag :type="jobStatusTagType(row.status)" size="small">
              {{ jobStatusLabel(row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="进度" width="140">
          <template #default="{ row }">
            {{ row.current_index }}/{{ row.total_rows }}
          </template>
        </el-table-column>
        <el-table-column label="成功/失败" width="140">
          <template #default="{ row }">
            <span class="text-success mr-2">{{ row.success_count }}</span
            >/ <span class="text-danger">{{ row.fail_count }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="created_at" label="创建时间" min-width="160" />
        <el-table-column prop="finished_at" label="完成时间" min-width="160" />
        <el-table-column label="操作" width="140">
          <template #default="{ row }">
            <el-button
              type="primary"
              link
              size="small"
              @click="openJobDetail(row)"
            >
              查看详情
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="job-pagination" v-if="jobState.pagination.total > 0">
        <el-pagination
          :current-page="jobState.pagination.currentPage"
          :page-size="jobState.pagination.pageSize"
          layout="prev, pager, next, jumper"
          :total="jobState.pagination.total"
          @current-change="handleJobPageChange"
        />
      </div>
    </el-card>

    <el-dialog
      v-model="jobState.dialogVisible"
      title="任务详情"
      width="600px"
      :destroy-on-close="true"
      @close="closeJobDetail"
    >
      <el-descriptions v-if="jobState.dialogJob" :column="2" border size="small">
        <el-descriptions-item label="任务ID">
          {{ jobState.dialogJob.id }}
        </el-descriptions-item>
        <el-descriptions-item label="状态">
          <el-tag :type="jobStatusTagType(jobState.dialogJob.status)" size="small">
            {{ jobStatusLabel(jobState.dialogJob.status) }}
          </el-tag>
        </el-descriptions-item>
        <el-descriptions-item label="总条数">
          {{ jobState.dialogJob.total_rows }}
        </el-descriptions-item>
        <el-descriptions-item label="成功/失败">
          {{ jobState.dialogJob.success_count }}/{{ jobState.dialogJob.fail_count }}
        </el-descriptions-item>
        <el-descriptions-item label="创建时间">
          {{ jobState.dialogJob.created_at }}
        </el-descriptions-item>
        <el-descriptions-item label="完成时间">
          {{ jobState.dialogJob.finished_at || "-" }}
        </el-descriptions-item>
      </el-descriptions>
      <el-divider />
      <template v-if="jobState.dialogErrors.length">
        <el-scrollbar max-height="300px" class="job-error-list">
          <el-alert
            v-for="(error, index) in jobState.dialogErrors"
            :key="index"
            :title="error"
            type="error"
            :closable="false"
            show-icon
            class="mb-2"
          />
        </el-scrollbar>
      </template>
      <el-empty v-else description="暂无错误信息" />
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import {
  computed,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref
} from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { UploadFilled } from "@element-plus/icons-vue";
import * as XLSX from "xlsx";
import productApi from "@/api/system/product/product";
import { useRouter } from "vue-router";
import type {
  ImportJobDetail,
  ImportJobItem,
  ImportJobListResult
} from "@/api/system/product/product";
import { fetchOrganizationList } from "@/api/system/org/organization";
import { useUserStoreHook } from "@/store/modules/user";

interface MappingField {
  key: string;
  label: string;
  required: boolean;
  mappedHeader: string | null;
  aliases?: string[];
}

interface ImportResultState {
  success: boolean;
  title: string;
  subTitle: string;
  jobId: number | null;
  errors: string[];
}

interface BulkUploadExecutionOptions {
  totalRows: number;
  validRowCount: number;
  mappingPayload: Record<string, string>;
  uploadFile: { raw: File; name: string };
  allowDuplicate: boolean;
}

const router = useRouter();
const userStore = useUserStoreHook();
const clientType = computed(
  () => (userStore.clientType ?? "admin").toLowerCase()
);
const showSellerOrgSelector = computed(
  () => !clientType.value.startsWith("seller")
);
const sellerOrgId = ref<number | null>(null);
const sellerOrgOptions = ref<Array<{ id: number; name: string }>>([]);
const sellerOrgLoading = ref(false);
const currentStep = ref(0);
const processing = ref(false);
const loadingPreview = ref(false);

const uploadFileList = ref<any[]>([]);

const resolveUploadFile = () => {
  const fileItem = uploadFileList.value[0];
  if (!fileItem || !fileItem.raw) {
    return null;
  }
  const rawFile = fileItem.raw as File;
  const filename =
    fileItem.name || (rawFile && "name" in rawFile ? rawFile.name : "") || "import.xlsx";
  return {
    raw: rawFile,
    name: filename
  };
};

const defaultMapping: MappingField[] = [
  {
    key: "title",
    label: "商品标题",
    required: false,
    mappedHeader: null,
    aliases: ["标题", "商品名称", "品名"]
  },
  {
    key: "subtitle",
    label: "副标题",
    required: false,
    mappedHeader: null,
    aliases: ["副标题", "短描述"]
  },
  {
    key: "model",
    label: "型号",
    required: true,
    mappedHeader: null,
    aliases: ["型号", "规格", "型号/规格"]
  },
  {
    key: "sku_code",
    label: "SKU编码",
    required: false,
    mappedHeader: null,
    aliases: ["SKU", "SKU码", "商品编码", "货号", "ID"]
  },
  {
    key: "default_price",
    label: "价格",
    required: true,
    mappedHeader: null,
    aliases: ["价格", "单价", "进货价", "售价"]
  },
  {
    key: "default_stock",
    label: "库存",
    required: true,
    mappedHeader: null,
    aliases: ["库存", "库存数量", "数量"]
  },
  {
    key: "unit",
    label: "单位",
    required: false,
    mappedHeader: null,
    aliases: ["单位", "计量单位"]
  },
  {
    key: "category_id",
    label: "分类ID",
    required: false,
    mappedHeader: null,
    aliases: ["分类ID", "类目ID"]
  },
  {
    key: "category_slug",
    label: "分类编码",
    required: false,
    mappedHeader: null,
    aliases: ["分类编码", "类目编码"]
  },
  {
    key: "category_name",
    label: "分类名称",
    required: false,
    mappedHeader: null,
    aliases: ["分类", "一级分类", "分类名称"]
  },
  {
    key: "category_level2",
    label: "二级分类名称",
    required: false,
    mappedHeader: null,
    aliases: ["二级分类", "子分类", "系列"]
  },
  {
    key: "category_path",
    label: "分类路径",
    required: false,
    mappedHeader: null,
    aliases: ["分类路径", "类目路径"]
  },
  {
    key: "brand_id",
    label: "品牌ID",
    required: false,
    mappedHeader: null,
    aliases: ["品牌ID"]
  },
  {
    key: "brand_name",
    label: "品牌名称",
    required: false,
    mappedHeader: null,
    aliases: ["品牌", "品牌名"]
  },
  {
    key: "brand_slug",
    label: "品牌编码",
    required: false,
    mappedHeader: null,
    aliases: ["品牌编码", "品牌代号"]
  },
  {
    key: "origin_country",
    label: "产地",
    required: false,
    mappedHeader: null,
    aliases: ["产地", "国家", "原产地"]
  },
  {
    key: "summary",
    label: "摘要",
    required: false,
    mappedHeader: null,
    aliases: ["摘要", "卖点", "包装"]
  },
  {
    key: "description",
    label: "描述",
    required: false,
    mappedHeader: null,
    aliases: ["描述", "详情", "说明", "内容"]
  },
  {
    key: "remark",
    label: "备注",
    required: false,
    mappedHeader: null,
    aliases: ["备注", "备注信息", "车型"]
  },
  {
    key: "status",
    label: "商品状态",
    required: false,
    mappedHeader: null,
    aliases: ["状态", "上架状态"]
  },
  {
    key: "audit_status",
    label: "审核状态",
    required: false,
    mappedHeader: null,
    aliases: ["审核状态"]
  }
];

const requiredFieldGroups = [
  {
    label: "分类（ID或名称）",
    keys: [
      "category_id",
      "category_slug",
      "category_name",
      "category_level2",
      "category_path"
    ]
  }
];

const templateColumns = [
  { header: "ID", example: "SKU0001" },
  { header: "品牌", example: "SKF" },
  { header: "型号", example: "22318E/C3" },
  { header: "标题", example: "轴承" },
  { header: "分类", example: "轴承" },
  { header: "二级分类", example: "调心滚子轴承" },
  { header: "进货价", example: 99.9 },
  { header: "库存", example: 100 },
  { header: "单位", example: "套" },
  { header: "产地", example: "进口" },
  { header: "包装", example: "新" },
  { header: "状态", example: "上架" },
  { header: "备注", example: "车型/备注信息" }
];

const normaliseHeader = (text: string) =>
  text.replace(/[\s_\-]/g, "").toLowerCase();

const mappingFields = ref<MappingField[]>(
  JSON.parse(JSON.stringify(defaultMapping))
);
const fileHeaders = ref<string[]>([]);
const fileRows = ref<Record<string, any>[]>([]);
const previewData = ref<Record<string, any>[]>([]);

const DUPLICATE_CONFIRM_TOKEN = "[DUPLICATE_IMPORT_CONFIRM]";

const importResult = reactive<ImportResultState>({
  success: false,
  title: "",
  subTitle: "",
  jobId: null,
  errors: []
});

const jobState = reactive({
  list: [] as ImportJobItem[],
  loading: false,
  pagination: {
    total: 0,
    pageSize: 10,
    currentPage: 1
  },
  dialogVisible: false,
  dialogJob: null as ImportJobDetail | null,
  dialogErrors: [] as string[]
});

let jobTimer: number | undefined;

const mappedPreviewFields = computed(() =>
  mappingFields.value.filter(field => field.mappedHeader)
);

const invalidRowCount = computed(() =>
  previewData.value.reduce((count, row) => {
    return count + (validateRow(row).valid ? 0 : 1);
  }, 0)
);

const isDuplicateConfirmError = (error: unknown): boolean => {
  const message =
    typeof error === "string"
      ? error
      : error && typeof (error as { message?: string }).message === "string"
      ? (error as { message?: string }).message ?? ""
      : "";
  return typeof message === "string" && message.includes(DUPLICATE_CONFIRM_TOKEN);
};

const extractDuplicateMessage = (message?: string): string => {
  if (!message) {
    return "检测到相同参数的导入任务，确认后请重试。";
  }
  const sanitized = message.replace(DUPLICATE_CONFIRM_TOKEN, "").trim();
  return sanitized || "检测到相同参数的导入任务，确认后请重试。";
};

const executeBulkUpload = async ({
  totalRows,
  validRowCount,
  mappingPayload,
  uploadFile,
  allowDuplicate
}: BulkUploadExecutionOptions) => {
  const formData = new FormData();
  formData.append("file", uploadFile.raw, uploadFile.name);
  formData.append("mapping", JSON.stringify(mappingPayload));
  formData.append(
    "options",
    JSON.stringify({
      preview_row_count: totalRows,
      valid_row_count: validRowCount,
      selected_headers: mappingPayload,
      headers: fileHeaders.value
    })
  );
  formData.append("total_rows", String(totalRows));
  formData.append("allow_duplicate", allowDuplicate ? "1" : "0");
  if (showSellerOrgSelector.value && sellerOrgId.value) {
    formData.append("seller_org_id", String(sellerOrgId.value));
  }

  const result = await productApi.bulkUpload(formData);
  const estimatedRows = result.total_rows || totalRows;
  importResult.success = true;
  importResult.jobId = result.job_id;
  importResult.title = result.duplicate ? "已复用相同任务" : "任务已创建";
  importResult.subTitle = `任务 ID ${result.job_id}，预计处理 ${estimatedRows} 条数据，系统将在后台执行`;
  importResult.errors = [];
  currentStep.value = 3;
  fetchJobList();
};

const numericFields = [
  "default_price",
  "default_stock",
  "category_id",
  "brand_id"
];

const getExampleValue = (header: string | null) => {
  if (!header) return "";
  const row = fileRows.value[0];
  if (!row) return "";
  return row[header] ?? "";
};

const resetFile = () => {
  uploadFileList.value = [];
  fileHeaders.value = [];
  fileRows.value = [];
  previewData.value = [];
  mappingFields.value = JSON.parse(JSON.stringify(defaultMapping));
};

const parseFile = async (file: File) => {
  const reader = new FileReader();
  const data = await new Promise<ArrayBuffer>((resolve, reject) => {
    reader.onload = e => {
      resolve(e.target?.result as ArrayBuffer);
    };
    reader.onerror = err => reject(err);
    reader.readAsArrayBuffer(file);
  });

  const workbook = XLSX.read(data, { type: "array" });
  const sheetName = workbook.SheetNames[0];
  const worksheet = workbook.Sheets[sheetName];
  const jsonData = XLSX.utils.sheet_to_json<Record<string, any>>(worksheet, {
    defval: ""
  });

  if (!Array.isArray(jsonData) || jsonData.length === 0) {
    throw new Error("未读取到有效的数据行");
  }

  fileRows.value = jsonData;
  fileHeaders.value = Object.keys(jsonData[0] ?? {});
};

const startJobPolling = () => {
  const hasPending = jobState.list.some(job =>
    ["pending", "running"].includes(job.status)
  );
  if (hasPending && !jobTimer) {
    jobTimer = window.setInterval(() => {
      fetchJobList();
    }, 10000);
  }
  if (!hasPending) {
    stopJobPolling();
  }
};

const stopJobPolling = () => {
  if (jobTimer) {
    clearInterval(jobTimer);
    jobTimer = undefined;
  }
};

const fetchJobList = async (page?: number) => {
  jobState.loading = true;
  try {
    const targetPage = page ?? jobState.pagination.currentPage ?? 1;
    const res = (await productApi.fetchImportJobs({
      page: targetPage,
      page_size: jobState.pagination.pageSize
    })) as ImportJobListResult;
    jobState.list = res.list;
    jobState.pagination.total = res.pagination.total;
    jobState.pagination.pageSize = res.pagination.pageSize;
    jobState.pagination.currentPage = res.pagination.currentPage;
    startJobPolling();
  } catch (error: any) {
    ElMessage.error(error?.message ?? "获取导入任务列表失败");
  } finally {
    jobState.loading = false;
  }
};

const handleJobPageChange = (page: number) => {
  fetchJobList(page);
};

const openJobDetail = async (job: ImportJobItem) => {
  try {
    const detail = await productApi.fetchImportJobDetail(job.id);
    jobState.dialogJob = detail;
    jobState.dialogErrors = detail.error_log ?? [];
    jobState.dialogVisible = true;
  } catch (error: any) {
    ElMessage.error(error?.message ?? "获取任务详情失败");
  }
};

const closeJobDetail = () => {
  jobState.dialogVisible = false;
  jobState.dialogJob = null;
  jobState.dialogErrors = [];
};

const jobStatusTagType = (status: string) => {
  switch (status) {
    case "success":
      return "success";
    case "failed":
      return "danger";
    case "running":
      return "warning";
    default:
      return "info";
  }
};

const jobStatusLabel = (status: string) => {
  switch (status) {
    case "success":
      return "已完成";
    case "failed":
      return "失败";
    case "running":
      return "执行中";
    case "pending":
      return "排队中";
    default:
      return status;
  }
};

const loadSellerOrgOptions = async (keyword?: string) => {
  sellerOrgLoading.value = true;
  try {
    const res = await fetchOrganizationList({
      page: 1,
      page_size: 20,
      org_type: "seller",
      keyword: keyword?.trim() || undefined
    });
    sellerOrgOptions.value = res.list.map(item => ({
      id: item.id,
      name: item.name || `组织 ${item.id}`
    }));
  } catch (error: any) {
    ElMessage.error(error?.message ?? "加载卖家组织失败");
  } finally {
    sellerOrgLoading.value = false;
  }
};

const ensureSellerOrgOptions = () => {
  if (!sellerOrgOptions.value.length) {
    loadSellerOrgOptions();
  }
};

const handleSellerOrgSearch = (keyword: string) => {
  loadSellerOrgOptions(keyword);
};

const handleSellerOrgVisibleChange = (visible: boolean) => {
  if (visible) {
    ensureSellerOrgOptions();
  }
};

const handleFileChange = async (file: any) => {
  if (!file.raw) return;
  try {
    await parseFile(file.raw);
    uploadFileList.value = [file];
    autoMapFields();
    buildPreviewData();
    ElMessage.success("文件解析成功");
  } catch (error: any) {
    resetFile();
    ElMessage.error(error?.message ?? "文件解析失败");
  }
};

const autoMapFields = () => {
  mappingFields.value.forEach(field => {
    if (field.mappedHeader) return;
    const candidates = [
      field.label,
      field.key,
      ...(field.aliases ?? [])
    ].map(normaliseHeader);
    const header = fileHeaders.value.find(item =>
      candidates.includes(normaliseHeader(item))
    );
    if (header) {
      field.mappedHeader = header;
    }
  });
  buildPreviewData();
};

const buildPreviewData = () => {
  if (!fileRows.value.length) {
    previewData.value = [];
    return;
  }
  const mapped = fileRows.value.map(sourceRow => {
    const rowByField: Record<string, any> = {};
    mappingFields.value.forEach(field => {
      if (field.mappedHeader) {
        rowByField[field.key] = sourceRow[field.mappedHeader];
      }
    });
    return transformRow(rowByField);
  });
  previewData.value = mapped;
};

const validateRow = (row: Record<string, any>) => {
  const errors: string[] = [];
  mappingFields.value.forEach(field => {
    const value = row[field.key];
    if (field.required) {
      if (value === undefined || value === null || value === "") {
        errors.push(`${field.label}不能为空`);
        return;
      }
    }
    if (
      value !== undefined &&
      value !== null &&
      value !== "" &&
      numericFields.includes(field.key)
    ) {
      const num = Number(value);
      if (Number.isNaN(num)) {
        errors.push(`${field.label}必须是数值`);
      } else if (field.key !== "default_price" && !Number.isInteger(num)) {
        errors.push(`${field.label}必须是整数`);
      }
    }
  });
  requiredFieldGroups.forEach(group => {
    const hasValue = group.keys.some(key => {
      const value = row[key];
      if (value === undefined || value === null) return false;
      if (typeof value === "string") {
        return value.trim() !== "";
      }
      return value !== "";
    });
    if (!hasValue) {
      errors.push(`${group.label}不能为空`);
    }
  });
  return {
    valid: errors.length === 0,
    errors
  };
};

const nextStep = () => {
  if (currentStep.value === 0) {
    if (!fileRows.value.length) {
      ElMessage.warning("请先上传数据文件");
      return;
    }
  } else if (currentStep.value === 1) {
    const missingRequired = mappingFields.value.filter(
      field => field.required && !field.mappedHeader
    );
    if (missingRequired.length) {
      ElMessage.warning(
        `请完成必填字段映射：${missingRequired.map(item => item.label).join("、")}`
      );
      return;
    }
    buildPreviewData();
  }
  currentStep.value += 1;
};

const prevStep = () => {
  if (currentStep.value > 0) {
    currentStep.value -= 1;
  }
};

const transformRow = (row: Record<string, any>) => {
  const payload: Record<string, any> = {};
  mappingFields.value.forEach(field => {
    let value = row[field.key];
    if (value === undefined || value === null || value === "") {
      return;
    }
    if (typeof value === "string") {
      value = value.trim();
      if (value === "") {
        return;
      }
    }
    if (numericFields.includes(field.key)) {
      const num =
        field.key === "default_price"
          ? Number(value)
          : parseInt(String(value), 10);
      payload[field.key] = Number.isNaN(num) ? value : num;
    } else {
      payload[field.key] = value;
    }
  });
  return payload;
};

const buildMappingPayload = () => {
  const mapping: Record<string, string> = {};
  mappingFields.value.forEach(field => {
    if (field.mappedHeader) {
      mapping[field.key] = field.mappedHeader;
    }
  });
  return mapping;
};

const handleImport = async () => {
  if (processing.value) return;
  const totalRows = previewData.value.length;
  if (!totalRows) {
    ElMessage.warning("没有可导入的数据");
    return;
  }

  if (showSellerOrgSelector.value && !sellerOrgId.value) {
    ElMessage.warning("请选择需要导入的卖家组织");
    return;
  }

  const validRows = previewData.value.filter(row => validateRow(row).valid);
  if (!validRows.length) {
    ElMessage.warning("校验未通过，无法导入");
    return;
  }

  const uploadFile = resolveUploadFile();
  if (!uploadFile) {
    ElMessage.warning("请重新上传文件后再试");
    return;
  }

  const mappingPayload = buildMappingPayload();
  if (!Object.keys(mappingPayload).length) {
    ElMessage.warning("请先完成字段映射");
    return;
  }

  const confirmMessage =
    validRows.length === totalRows
      ? `文件共 ${totalRows} 条数据，确定创建导入任务吗？`
      : `文件共 ${totalRows} 条数据，其中 ${validRows.length} 条通过初步校验，确定继续创建导入任务吗？`;

  try {
    await ElMessageBox.confirm(confirmMessage, "确认导入", {
      type: "warning",
      confirmButtonText: "确定",
      cancelButtonText: "取消"
    });
  } catch {
    return;
  }

  processing.value = true;
  importResult.success = false;
  importResult.title = "";
  importResult.subTitle = "";
  importResult.jobId = null;
  importResult.errors = [];

  try {
    await executeBulkUpload({
      totalRows,
      validRowCount: validRows.length,
      mappingPayload,
      uploadFile,
      allowDuplicate: false
    });
  } catch (error: any) {
    if (isDuplicateConfirmError(error)) {
      const confirmMessage = extractDuplicateMessage(error.message);
      try {
        await ElMessageBox.confirm(
          confirmMessage,
          "检测到重复导入",
          {
            type: "warning",
            confirmButtonText: "继续导入",
            cancelButtonText: "取消"
          }
        );
        await executeBulkUpload({
          totalRows,
          validRowCount: validRows.length,
          mappingPayload,
          uploadFile,
          allowDuplicate: true
        });
        return;
      } catch {
        ElMessage.info("已取消重复导入");
        return;
      }
    }
    importResult.success = false;
    importResult.title = "任务创建失败";
    importResult.subTitle = error?.message ?? "请稍后重试";
    importResult.errors = [importResult.subTitle];
    currentStep.value = 3;
  } finally {
    processing.value = false;
  }
};

const resetAll = () => {
  currentStep.value = 0;
  processing.value = false;
  loadingPreview.value = false;
  resetFile();
  importResult.success = false;
  importResult.title = "";
  importResult.subTitle = "";
  importResult.jobId = null;
  importResult.errors = [];
  if (showSellerOrgSelector.value) {
    sellerOrgId.value = null;
  }
  fetchJobList();
};

const backToList = () => {
  router.push({ path: "/product/list" }).catch(() => undefined);
};

const downloadTemplate = () => {
  const headers = templateColumns.map(column => column.header);
  const example = templateColumns.map(column => column.example);

  const worksheet = XLSX.utils.aoa_to_sheet([headers, example]);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, "模板");
  XLSX.writeFile(workbook, "产品导入模板.xlsx");
};

onMounted(() => {
  if (showSellerOrgSelector.value) {
    loadSellerOrgOptions();
  }
  fetchJobList();
});

onBeforeUnmount(() => {
  stopJobPolling();
});
</script>

<style scoped>
.product-bulk-upload {
  padding: 12px;
}

.step-section {
  margin-top: 24px;
}

.config-form {
  margin-top: 16px;
}

.upload-box {
  width: 100%;
}

.required-label {
  font-weight: 600;
}

.required-marker {
  color: var(--el-color-danger);
  margin-left: 4px;
}

.error-panel {
  margin-top: 16px;
}

.step-actions {
  margin-top: 24px;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.job-card {
  margin-top: 16px;
}

.job-pagination {
  margin-top: 16px;
  display: flex;
  justify-content: flex-end;
}

.job-error-list {
  padding-right: 8px;
}

.text-success {
  color: var(--el-color-success);
}

.text-danger {
  color: var(--el-color-danger);
}
</style>
